{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 回调处理器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 为什么要用回调处理器？\n",
    "- 模块化和可重用性：例如，如果你有多个应用都需要流式输出到WebSocket，那么使用一个统一的`WebSocketStreamingHandler`可以避免可重复的代码。\n",
    "- 灵活性：回调处理器提供了一种结构化的方式来响应各种时间，而不仅仅是流式输出。这意味着你可以为各种事件（如链开始、结束、错误发生等）定义特动的逻辑。\n",
    "- 与LangChain框架中的其他组件紧密集成：回调处理器是为LangChain框架的特别设计，确保其内部机制的兼容性和高效性。\n",
    "- 代码清晰且具有维护性：通过使用专门的回调处理器，你的代码结构会更清晰。当其他开发者查看或维护你的代码时，他们可以轻松地找到和理解回调逻辑。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 回调处理器的工作流程\n",
    "- `run_manager`用于管理和触发回调事件\n",
    "- `callbacks=[]`表示的是为`run_manager`提供的回调处理器列表"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 回调处理器的四个过程\n",
    "- 开始执行链组件：此时，系统开始执行链组件，并为处理输入数据做好准备。然后检查`callbakcs=[]`参数，若传递了`callbacks=[]`，则系统进入下一步初始化`run_manager`。此时，系统使用传递的`callbacks=[]`列表来初始化`run_manager`，确保它包含了所有提供的回调参数器。\n",
    "- 链组件执行中阶段：系统根据输入数据执行链组件。在各个关键节点，如数据处理、模型调用等，系统会检查`run_manager`是否需要触发任何回调。\n",
    "- 触发回调截断：如果`run_manager`在某个执行阶段检测到需要触发的回调事件，它会按照`callbacks=[]`中定义的顺序触发回调处理器。\n",
    "- 完成阶段：当所有任务都完成，并且所有必要的回调都被触发后，链组件的执行就此结束。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![回调工作流](./CallBackWorkFlow.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### LangChain中内置的回调处理器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入必要的组件与函数\n",
    "from langchain.agents import load_tools\n",
    "from langchain.agents import initialize_agent\n",
    "from langchain.agents import AgentType\n",
    "from langchain.llms import OpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载LLM，工具和智能体\n",
    "llm = OpenAI()\n",
    "tools = load_tools([\"serpapi\"],llm=llm)\n",
    "agent = initialize_agent(\n",
    "    llm = llm,\n",
    "    tools = tools,\n",
    "    agent = AgentType.ZERO_SHOT_REACT_DESCRIPTION,\n",
    "    verbose = True\n",
    ")\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m 研究Quake游戏的开发者和技术实现可能会提供有用的信息。\n",
      "Action: Search\n",
      "Action Input: \"Quake game developer and technical implementation\"\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3m['Quake is a first-person shooter game developed by id Software and published by GT Interactive. The first game in the Quake series, it was originally ...', 'This page documents information about a third-party game running on a non-Valve engine. This information is documented here because it has ...', 'The Quake engine is the game engine developed by id Software to power their 1996 video game Quake. It featured true 3D real-time rendering.', \"If you want to be a game programmer, or for that matter any sort of programmer at all, here's the secret to success in just two words: Ship it.\", \"Planning and implementing Quake's pipeline was the biggest technical ... Amateur game developer ... technology, are we going to innovate in our game ...\", \"Let's play a game. Suppose that you are a software developer and have just been hired onto the Quake Champions team. What do you do first?\", 'Game Developer is part of the Informa Tech Division of Informa PLC ... The code to implement this can be found on the Game Developer web site.', 'qtas files. FTEQW - Source port focused on standalone game development. Notably includes clean-room implementations of GoldSrc file formats ...', 'Around March of 1995, Kevin Cloud created some of the very first models for Quake, a human model which consisted of around 200 polygons, using the DooM Cyber- ...', \"With Quake's underlying tech finally in place, Romero was ready to move on from what he viewed as R&D into full development and to create a game ...\"]\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m The results seem to suggest that Quake used its own game engine developed by id Software and had a team dedicated to implementing it.\n",
      "Action: Search\n",
      "Action Input: \"Quake game engine implementation\"\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3m[\"There's an active Quake modding community. Start by checking it out. A brand new game based on the Quake engine can start out as a Quake mod. If ...\", \"I am writing because I love old games' climate and I want to create something like Quake 1 for my own (mathematical/physical/3D) experience. I ...\", 'This page documents information about a third-party game running on a non-Valve engine. This information is documented here because it has ...', 'The Quake engine is the game engine developed by id Software to power their 1996 video game Quake. It featured true 3D real-time rendering.', 'To get started, download the source code for an engine. This might be available as a compressed package or in a revision control repository. Make sure your ...', 'A source port is a port of the source code for the Quake engine (originally only available for DOS platforms) to other platforms.', 'This is the complete source code for winquake, glquake, quakeworld, and glquakeworld. The projects have been tested with visual C++ 6.0, but masm is also ...', 'The eventual solution, implemented by the Quake III engine, was to combine the advantages of original QuakeC with the advantages of compiling C to native code.']\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m It seems like the Quake game engine was created specifically for the game and has been modified and expanded upon by various developers over the years.\n",
      "Action: Search\n",
      "Action Input: \"evolution of Quake game engine\"\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3m['The Quake engine was developed from 1995 for the video game Quake, released on June 22, 1996. John Carmack did most of the programming of the engine, with help ...', 'Quake was one of the earliest true 3D games on the PC, at least in an optimised sense. This optimisation was thanks to several more technical ...', '\"idtech 3\" is the retroactive name for the quake 3 engine, so you were right. The source engine rewrote a lot of goldsrc (the Half-Life engine) ...', \"The game engine (a.k.a. Quake engine or just engine) is the 'executable' program you run to actually play Quake. It loads the game's maps ...\", 'The first game in the Quake series, it was originally released for MS-DOS, Microsoft Windows and Linux in 1996, followed by Mac OS and Sega Saturn in 1997 and ...', 'A rough guide to the varieties of Quake. This is not a step-by-step recipe, but rather some info to help you decide what you want to do....', 'After the release of DooM II, work started on an engine that would eventually become the Quake Engine. On August 8th, 1994 what would become known as QuakeC was ...', 'Quake traces its origins back to a promotion in the first Commander Keen trilogy, where it was titled Quake: The Fight For Justice. The player was named ...']\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m It appears that the Quake game engine has evolved over time, with John Carmack being the primary programmer for the original version.\n",
      "Thought: I now know the final answer\n",
      "Final Answer: The Quake game engine was developed specifically for the game by id Software, with John Carmack being the primary programmer for the original version. It has since been modified and expanded upon by various developers over the years. \u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'The Quake game engine was developed specifically for the game by id Software, with John Carmack being the primary programmer for the original version. It has since been modified and expanded upon by various developers over the years.'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent.run(\"在Quake中的快速算术平方根是如何实现的？\")\n",
    "# 由于此时智能体开启了verbose，因此会调用StdCallbackProcessor\n",
    "# 并显示模型的推理过程"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n\\n1. 沈阳故宫：被誉为“北方的故宫”，是清代皇宫建筑的杰作，也是世界上保存最完整的皇家建筑群之一。\\n\\n2. 沈阳市中心街：又称“中街”，是沈阳市最繁华的商业街，拥有众多历史建筑和现代商业设施，是游客购物和品尝美食的热门地点。\\n\\n3. 朝阳湖公园：是沈阳市最大的城市公园，也是沈阳市民休闲娱乐的主要场所，湖光山色、花木扶疏，是赏花、散步、垂钓的好去处。\\n\\n4. 沈阳森林动物园：位于沈阳市北部，是中国最大的城市'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 现在构建一个带有verbose的智能体\n",
    "from langchain.prompts import PromptTemplate\n",
    "from langchain.chains import LLMChain\n",
    "from langchain.llms import OpenAI\n",
    "\n",
    "# 创建LLM链\n",
    "llm_chain = LLMChain(\n",
    "    llm = OpenAI(),\n",
    "    prompt = PromptTemplate.from_template(\"{input}\")\n",
    ")\n",
    "\n",
    "llm_chain.run(\"沈阳的著名旅游景点有哪些？\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3m沈阳的著名旅游景点有哪些？\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\n\\n1. 沈阳故宫\\n2. 北陵公园\\n3. 东陵公园\\n4. 凌河公园\\n5. 沈阳植物园\\n6. 沈阳森林动物园\\n7. 沈阳世博园\\n8. 现代汽车博物馆\\n9. 沈阳市博物馆\\n10. 沈阳草莓主题公园\\n11. 长白山风景名胜区\\n12. 沈阳八一罗马广场\\n13. 沈阳市图书馆\\n14. 沈阳博物院\\n15. 沈阳大悦城\\n16. 沈阳海洋极地世界\\n17. 沈阳悦泉国际水城\\n18. 沈阳皇家度假村\\n19. 沈阳太阳岛风景'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 导入StdCallbackHandler以监听llm_chain的输出\n",
    "from langchain.callbacks import StdOutCallbackHandler\n",
    "handler = StdOutCallbackHandler()\n",
    "\n",
    "llm_chain = LLMChain(\n",
    "    llm = OpenAI(),\n",
    "    prompt = PromptTemplate.from_template(\"{input}\"),\n",
    "    callbacks=[handler]\n",
    ")\n",
    "\n",
    "llm_chain.run(\"沈阳的著名旅游景点有哪些？\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    " "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
